<?php

declare (strict_types=1);

namespace app;

use app\http\middleware\AddLog;
use app\http\middleware\Auth;
use app\http\middleware\ValidateParams;
use randy\tools\units\ExtendQueryHelper;
use think\App;
use think\Model;
use think\response\Json;

/**
 * 控制器基础类
 */
abstract class BaseController
{
    /**
     * Request实例
     */
    protected \think\Request $request;

    /**
     * 应用实例
     */
    protected App $app;

    protected mixed $params = [];
    /**
     * 快速搜索时执行查找的字段.
     */
    protected string $searchFields = 'id';
    /**
     * 是否是关联查询.
     */
    protected bool $relationSearch = false;


    /**
     * 控制器中间件
     *
     * @var array
     */
    protected $middleware = [Auth::class, ValidateParams::class, AddLog::class];

    /**
     * 构造方法
     *
     * @access public
     *
     * @param App $app 应用对象
     */
    public function __construct(App $app)
    {
        $this->app = $app;
        $this->request = $this->app->request;
        $params = $this->request->post();
        unset($params['trans_id']);
        unset($params['appkey']);
        unset($params['token']);
        unset($params['timestamp']);
        $this->params = $params;
        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize()
    {
    }

    public function success($result = [], $msg = 'SUCCESS', int $code = 0) : Json
    {
        return \json(compact('code', 'msg', 'result'));
    }

    public function error($result = [], $msg = 'SUCCESS', int $code = 0) : Json
    {
        return \json(compact('code', 'msg', 'result'));
    }

    public function returnSuccess($result = true, $msg = 'SUCCESS', int $code = 0) : Json
    {
        return \json(compact('code', 'msg', 'result'));
    }

    public function returnError($result = [], $msg = 'SUCCESS', int $code = 0) : Json
    {
        return \json(compact('code', 'msg', 'result'));
    }

    public function getParams()
    {
        $params = $this->request->param();
        unset($params['trans_id']);
        unset($params['appkey']);
        unset($params['token']);
        unset($params['timestamp']);
        unset($params['is_debug']);
        unset($params['api_debug']);
        unset($params['XDEBUG_SESSION_START']);
        unset($params['app_key']);
        unset($params['file']);
        unset($params['create_time']);
        unset($params['update_time']);

        return $params;
    }


    /**
     * 生成查询所需要的条件,排序方式.
     *
     * @param mixed|null $searchfields   快速查询的字段
     * @param bool       $relationSearch 是否关联查询
     *
     * @return
     */
    protected function buildParams(mixed $searchfields = null, $model = null)
    {
        $model = $model ?: $this->model;
        $params = $this->getParams();


        $searchfields = $searchfields ?: ($params['search_field'] ?? '');
        $relationSearch = true;
        $search = $params['search'] ?? '';
        $filter = $params['filter'] ?? [];
        $op = $params['op'] ?? '';
        $sort = $params['order_field'] ?? '';
        $order = $params['order_type'] ?? 'DESC';
        $is_page = $params['is_page'] ?? '1';
        $order_combination = $params['order_combination'] ?? '';
        $filter = is_string($filter) ? json_decode($filter, true) : $filter;
        $op = is_string($op) ? json_decode($op, true) : $op;
        $where = [];
        $sort = $sort ?: ($model instanceof Model && $model->getPk() ? $model->getPk() : 'id');


        $tableName = '';
        if (!empty($model)) {
            $name = $model->getTable();
            $tableName = trim($name) . '.';
        }
        $sortArr = explode(',', $sort);
        foreach ($sortArr as $index => &$item) {
            $item = stripos($item, '.') === false ? $tableName . trim($item) : $item;
        }

        unset($item);
        $sort = implode(',', $sortArr);
        //        $adminIds = $this->getDataLimitAdminIds();
        //        if (is_array($adminIds)) {
        //            $where[] = [$tableName.$this->dataLimitField, 'in', $adminIds];
        //        }
        if ($search) {
            if ($searchfields) {
                $searcharr = is_array($searchfields) ? $searchfields : explode('|', $searchfields);
                foreach ($searcharr as &$v) {
                    $v = stripos($v, '.') === false ? $tableName . $v : $v;
                }
                unset($v);
                $where[] = [implode('|', $searcharr), 'LIKE', "%{$search}%"];
            }

        }
        foreach ($filter as $v) {
            $k = $v['field'];
            $value = $v['value'];
            if ($v['value'] === '' || $v['value'] === [] || $v['value'] ===null) {
                continue;
            }
            $sym = $v["op"] ?? '=';
            if (stripos($k, '.') === false) {
                $k = $tableName . $k;
            }
            $value = !is_array($value) ? trim((string)$value) : $value;
            $sym = strtoupper($v["op"] ?? $sym);
            if($value ===''){
                break;
            }
            switch ($sym) {
                case ' = ':
                case '=':
                case ' <> ':
                case '<>':
                    $where[] = [$k, $sym, (string)$value];
                    break;
                case 'LIKE':
                case 'NOT LIKE':
                case 'LIKE %...%':
                case 'NOT LIKE %...%':
                    $where[] = [$k, trim(str_replace(' %...%', '', $sym)), "%{$value}%"];
                    break;
                case ' > ':
                case '>':
                case '>=':
                case ' < ':
                case '<':
                case '<=':
                    $where[] = [$k, $sym, $value];
                    break;
                case 'FINDIN':
                case 'FINDINSET':
                case 'FIND_IN_SET':
                    $where[] = "FIND_IN_SET('$value', " . ($relationSearch ? $k : '`' . str_replace('.', '` . `', $k) . '`') . ')';
                    break;
                case 'IN':
                case 'IN(...)':
                case 'NOT IN':
                case 'NOT IN(...)':
                    $where[] = [$k, str_replace('(...)', '', $sym), is_array($value) ? $value : explode(',', $value)];
                    break;
                case 'BETWEEN':
                case 'NOT BETWEEN':
                    $between_arr = is_array($value) ? $value : explode(',', $value);
                    $arr = array_slice($between_arr, 0, 2);
                    //当出现一边为空时改变操作符
                    if ($arr[0] === '') {
                        $sym = $sym == 'BETWEEN' ? ' <= ' : '>';
                        $arr = $arr[1];
                    } elseif ($arr[1] === '') {
                        $sym = $sym == 'BETWEEN' ? ' >= ' : '<';
                        $arr = $arr[0];
                    }
                    $where[] = [$k, $sym, $arr];
                    break;
                case 'RANGE':
                case 'NOT RANGE':
                    $value = str_replace(' - ', ',', $value);
                    $arr = array_slice(explode(',', $value), 0, 2);
                    if (stripos($value, ',') === false || !array_filter($arr)) {
                        continue 2;
                    }
                    //当出现一边为空时改变操作符
                    if ($arr[0] === '') {
                        $sym = $sym == 'RANGE' ? ' <= ' : '>';
                        $arr = $arr[1];
                    } elseif ($arr[1] === '') {
                        $sym = $sym == 'RANGE' ? ' >= ' : '<';
                        $arr = $arr[0];
                    }
                    $where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' time', $arr];
                    break;
                case 'NULL':
                case 'IS NULL':
                case 'NOT NULL':
                case 'IS NOT NULL':
                    $where[] = [$k, strtolower(str_replace('IS ', '', $sym)), ''];
                    break;
                default:
                    break;
            }
        }
        if ($order_combination) {
            $sort = $order_combination;
            $order = '';
        }
        return new ExtendQueryHelper([
            "where"   => $where,
            'sort'    => trim($sort),
            'order'   => trim($order),
            'is_page' => $is_page
        ]);
    }

}
